package com.jsbs.iam.user.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.jsbs.iam.common.core.dto.Result;
import com.jsbs.iam.common.core.utils.Json;
import com.jsbs.iam.common.core.utils.StringUtils;
import com.jsbs.iam.common.redis.service.RedisUtils;
import com.jsbs.iam.user.constant.RedisConstants;
import com.jsbs.iam.user.entity.*;
import com.jsbs.iam.user.mapper.*;
import com.jsbs.iam.user.param.AdminRoleParam;
import com.jsbs.iam.user.service.IamAdminRoleService;
import com.jsbs.iam.user.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class IamAdminRoleServiceImpl implements IamAdminRoleService {

    @Autowired
    private IamAdminRoleMapper iamAdminRoleMapper;

    @Autowired
    private OrgInfoMapper orgInfoMapper;

    @Autowired
    private IamMenuMapper iamMenuMapper;

    @Autowired
    private IamApplySystemMapper iamApplySystemMapper;

    @Resource
    private RedissonClient redissonClient;

    @Autowired
    private IamApplyMenuMapper iamApplyMenuMapper;

    @Autowired
    private IamAdminRoleUserInfoMapper iamAdminRoleUserInfoMapper;

    @Value("${_env.name}")
    private String envName;

    @Override
    public PageInfo<AdminRoleInfoVo> queryForPage(AdminRoleParam adminRoleParam) {
        // 设置分页参数
        PageHelper.startPage(adminRoleParam.getPageNum(), adminRoleParam.getPageSize());
        List<Long> roleIds;
        // 获取组织对应的角色ID
        if (StringUtils.isNotEmpty(adminRoleParam.getOrgName())) {
            // 根据组织名称获取对应角色ID
            roleIds = orgInfoMapper.queryByOrgName(adminRoleParam.getOrgName());
            if (CollectionUtils.isEmpty(roleIds)) {
                return new PageInfo<>();
            }
            adminRoleParam.setRoleIds(roleIds);
        }
        // 查询列表
        List<AdminRoleInfoVo> roleInfoList = iamAdminRoleMapper.queryList(adminRoleParam);
        // 返回空
        if (CollectionUtils.isEmpty(roleInfoList)) {
            return new PageInfo<>();
        }
        PageInfo<AdminRoleInfoVo> pageInfo = new PageInfo<>(roleInfoList);
        // 循环封装 菜单权限列表 组织权限列表 应用权限列表
        pageInfo.getList().forEach(item -> {
            // 根据id 获取菜单权限列表
            List<AdminRoleMenuVo> menuList = iamApplyMenuMapper.getMenuList(item.getId());
            if (CollectionUtils.isNotEmpty(menuList)) {
                menuList.forEach(info -> {
                    // 根据菜单+角色获取按钮列表
                    info.setButtonList(iamApplyMenuMapper.getButtonList(info.getMenuId(), info.getRoleId()));
                });
                item.setMenuList(menuList);
            }
            // 根据id 获取组织权限列表
            List<AdminRoleOrgVo> adminOrgList = orgInfoMapper.getOrgList(item.getId());
            if (CollectionUtils.isNotEmpty(adminOrgList)) {
                item.setOrgList(adminOrgList);
            }
            // 根据id 获取应用权限列表
            List<AdminRoleApplyVo> applyList = iamApplySystemMapper.getApplyList(item.getId());
            if (CollectionUtils.isNotEmpty(applyList)) {
                item.setApplyList(applyList);
            }
        });
        // 返回分页数据
        return pageInfo;
    }

    @Override
    @Transactional
    public Result saveAdminRole(AdminRoleInfoVo adminRoleInfoVo, String userName) {
        // 校验入参
        Result result = checkForAdminRole(adminRoleInfoVo);
        // 入参校验失败，返回失败信息
        if (!result.isSuccess()) {
            log.warn("Route=>IamAdminRoleServiceImpl method=>saveAdminRole 管理员角色保存入参校验失败，入参info：{}，失败info：{}", Json.toJsonString(adminRoleInfoVo), result.getMsg());
            return result;
        }
        IamAdminRoleInfo adminRoleInfo = new IamAdminRoleInfo();
        BeanUtils.copyProperties(adminRoleInfoVo, adminRoleInfo);
        adminRoleInfo.setUpdatePerson(userName);
        // 主键不为空则更新
        if (Objects.nonNull(adminRoleInfoVo.getId())) {
            // 更新时权限数据先删除后入表
            // 更新角色
            iamAdminRoleMapper.updateById(adminRoleInfo);
            // 删除菜单权限
            iamMenuMapper.deleteByRoleId(adminRoleInfoVo.getId());
            // 删除组织权限
            orgInfoMapper.deleteByRoleId(adminRoleInfoVo.getId());
            // 删除应用权限
            iamApplySystemMapper.deleteByRoleId(adminRoleInfoVo.getId());
        } else {
            // 新增管理员角色
            // 生成角色编码
            adminRoleInfo.setAdminRoleCode(generateRoleCode());
            adminRoleInfo.setCreatePerson(userName);
            iamAdminRoleMapper.insert(adminRoleInfo);
        }
        // 批量新增菜单权限
        List<IamAdminRoleMenuInfo> menuInfoList = new ArrayList<>();
        List<IamAdminRoleButtonInfo> buttonInfoList = new ArrayList<>();
        adminRoleInfoVo.getMenuList().forEach(item -> {
            IamAdminRoleMenuInfo menuInfo = new IamAdminRoleMenuInfo();
            BeanUtils.copyProperties(item, menuInfo);
            menuInfo.setRoleId(adminRoleInfo.getId());
            menuInfo.setCreatePerson(userName);
            menuInfoList.add(menuInfo);
            item.getButtonList().forEach(info -> {
                IamAdminRoleButtonInfo buttonInfo = new IamAdminRoleButtonInfo();
                BeanUtils.copyProperties(info, buttonInfo);
                buttonInfo.setRoleId(adminRoleInfo.getId());
                buttonInfo.setMenuId(item.getMenuId());
                buttonInfo.setCreatePerson(userName);
                buttonInfoList.add(buttonInfo);
            });
        });
        if (CollectionUtils.isNotEmpty(menuInfoList)) {
            iamMenuMapper.batchInsertAdminMenu(menuInfoList);
        }
        if (CollectionUtils.isNotEmpty(buttonInfoList)) {
            iamMenuMapper.batchInsertAdminButton(buttonInfoList);
        }
        // 批量新增组织权限
        List<IamAdminRoleOrgInfo> orgInfoList = new ArrayList<>();
        adminRoleInfoVo.getOrgList().forEach(item -> {
            IamAdminRoleOrgInfo orgInfo = new IamAdminRoleOrgInfo();
            BeanUtils.copyProperties(item, orgInfo);
            orgInfo.setRoleId(adminRoleInfo.getId());
            orgInfo.setCreatePerson(userName);
            orgInfoList.add(orgInfo);
        });
        orgInfoMapper.batchInsertAdminOrg(orgInfoList);
        // 批量新增应用权限
        List<IamAdminRoleApplyInfo> applyInfoList = new ArrayList<>();
        adminRoleInfoVo.getApplyList().forEach(item -> {
            IamAdminRoleApplyInfo applyInfo = new IamAdminRoleApplyInfo();
            BeanUtils.copyProperties(item, applyInfo);
            applyInfo.setRoleId(adminRoleInfo.getId());
            applyInfo.setCreatePerson(userName);
            applyInfoList.add(applyInfo);
        });
        iamApplySystemMapper.batchInsertAdminApply(applyInfoList);
        return result;
    }

    /**
     * 功能描述：创建管理员角色编码
     * @return
     */
    private String generateRoleCode(){
        // 新增用户生成用户ID时加锁，失效时间10分钟
        RLock lock = redissonClient.getLock(RedisConstants.ADMIN_ROLE_CODE_LOCK);
        Long code = null;
        try {
            // 5分钟内重试获取锁，10秒后释放
            boolean isLocked = lock.tryLock(5 * 60 * 1000L, 10 * 1000L, TimeUnit.MILLISECONDS);
            // 获取到锁后，进行自增
            if (!isLocked) {
                log.warn("Route=>IamAdminRoleServiceImpl method=>generateRoleCode 新增管理员角色生成角色编码获取锁失败");
                throw new Exception();
            }
            // 加锁成功后获取当前缓存值
            String value = RedisUtils.get(envName + RedisConstants.ADMIN_ROLE_CODE);
            // 若为空则从数据库取当前最大值，并加新增用户数量入缓存
            if (StringUtils.isEmpty(value)) {
                code = Long.valueOf(iamAdminRoleMapper.getMaxRoleCode()) + 1;
            } else {
                // 当前缓存获取成功，并加新增用户数量入缓存
                code = Long.parseLong(value) + 1;
            }
            // 将最新值更新到缓存中
            RedisUtils.set(envName + RedisConstants.ADMIN_ROLE_CODE, String.valueOf(code));
        } catch (Exception e) {
            log.error("Route=>IamAdminRoleServiceImpl method=>generateRoleCode 新增管理员角色加锁生成角色编码失败:", e);
            throw new RuntimeException("生成管理员角色编码异常");
        } finally {
            // 手动解锁
            if (lock.isLocked()) {
                lock.unlock();
            }
        }
        return "JS".concat(String.format("%04d", code));
    }

    /**
     * 功能描述：保存管理员角色时入参校验
     * @param adminRoleInfoVo
     * @return
     */
    private Result checkForAdminRole(AdminRoleInfoVo adminRoleInfoVo){
        if (StringUtils.isEmpty(adminRoleInfoVo.getAdminRoleName())) {
            return Result.failWithMsg("角色名称为空");
        }
        if (CollectionUtils.isEmpty(adminRoleInfoVo.getMenuList())) {
            return Result.failWithMsg("菜单权限列表为空");
        }
        if (CollectionUtils.isEmpty(adminRoleInfoVo.getOrgList())) {
            return Result.failWithMsg("数据权限列表为空");
        }
        if (CollectionUtils.isEmpty(adminRoleInfoVo.getApplyList())) {
            return Result.failWithMsg("应用权限列表为空");
        }
        // 管理员角色已删除，无法编辑
        if (Objects.nonNull(adminRoleInfoVo.getId())) {
            // 根据id查询管理员角色
            IamAdminRoleInfo adminRoleInfo = iamAdminRoleMapper.queryById(adminRoleInfoVo.getId());
            if (Objects.isNull(adminRoleInfo)) {
                return Result.failWithMsg("管理员角色不存在，保存失败");
            }
            if (1 == adminRoleInfo.getDeleted()) {
                return Result.failWithMsg("管理员角色已删除，无法保存");
            }
        }
        return Result.success();
    }

    @Override
    public Result adminRoleStatusEdit(AdminRoleStatusVo adminRoleStatusVo, String userName) {
        if (Objects.isNull(adminRoleStatusVo.getStatus())) {
            return Result.failWithMsg("状态为空");
        }
        if (CollectionUtils.isEmpty(adminRoleStatusVo.getIds())) {
            return Result.failWithMsg("角色主键为空");
        }
        // 批量更新角色状态 启用/停用
        iamAdminRoleMapper.updateForStatus(adminRoleStatusVo, userName);
        return Result.success();
    }

    @Override
    public Result adminRoleBatchDelete(AdminRoleStatusVo adminRoleStatusVo, String userName) {
        if (CollectionUtils.isEmpty(adminRoleStatusVo.getIds())) {
            return Result.failWithMsg("角色主键为空");
        }
        // 批量删除
        iamAdminRoleMapper.batchDelete(adminRoleStatusVo.getIds(), userName);
        // 删除绑定的人员
        iamAdminRoleUserInfoMapper.deleteByRoleId(adminRoleStatusVo.getIds(), userName);
        // 删除绑定的菜单
        iamAdminRoleMapper.deleteMenuByRoleId(adminRoleStatusVo.getIds(), userName);
        // 删除绑定的按钮
        iamAdminRoleMapper.deleteButtonByRoleId(adminRoleStatusVo.getIds(), userName);
        // 删除绑定的应用
        iamAdminRoleMapper.deleteApplyByRoleId(adminRoleStatusVo.getIds(), userName);
        // 删除绑定的组织
        iamAdminRoleMapper.deleteOrgByRoleId(adminRoleStatusVo.getIds(), userName);
        // todo 删除角色时是否需要强制将角色下绑定的管理员用户强制退出登录
        return Result.success();
    }

    @Override
    public Result adminRoleUserBind(AdminRoleUserVo adminRoleUserVo, String userName) {
        if (CollectionUtils.isEmpty(adminRoleUserVo.getUserAccountList())) {
            return Result.failWithMsg("用户编码为空");
        }
        if (Objects.isNull(adminRoleUserVo.getRoleId())) {
            return Result.failWithMsg("角色ID为空");
        }
        // 绑定用户
        if (adminRoleUserVo.isBindFlag()) {
            List<String> userCodeList = new ArrayList<>();
            adminRoleUserVo.getUserAccountList().forEach(item -> {
                // 当前绑定是否已存在
                if (iamAdminRoleMapper.countByUserCode(adminRoleUserVo.getRoleId(), item.getUserCode()) <= 0) {
                    userCodeList.add(item.getUserCode());
                }
            });
            // 批量绑定新增用户
            if (CollectionUtils.isNotEmpty(userCodeList)) {
                iamAdminRoleMapper.bindUser(adminRoleUserVo.getRoleId(), adminRoleUserVo.getUserAccountList(), userName);
            }
        } else {
            // 批量解绑用户
            iamAdminRoleMapper.unBindUser(adminRoleUserVo.getRoleId(), adminRoleUserVo.getUserAccountList(), userName);
        }
        return Result.success();
    }

    @Override
    public List<AdminUserRoleVo> getAdminRoleByUser(String account){
        if (StringUtils.isEmpty(account)) {
            return new ArrayList<>();
        }
        return iamAdminRoleUserInfoMapper.getAdminRoleByUser(account);
    }
}
